package com.mocha.websocket;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.mocha.websocket.command.CommandModelMapping;
import com.mocha.websocket.handler.HandlerMapping;
import com.mocha.websocket.handler.MochaSocketCloseHandler;
import com.mocha.websocket.handler.MochaSocketConnectHandler;
import com.mocha.websocket.handler.MochaTextListener;
import com.mocha.websocket.metadata.MochaServerParameter;
import com.mocha.websocket.metadata.MochaSocketConfigProperties;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * @author songkui
 * @since 2024/3/16 10:35
 */
@Slf4j
public class MochaWebSocketServer {


    public void start(MochaSocketConfigProperties configProperties) {
        final SocketIOServer server = new SocketIOServer(buildConfiguration(configProperties));
        MochaWebSocketExecutor.getInstance().start();
        Set<MochaServerParameter> paramList = CommandModelMapping.getServerParamSet();
        if (CollectionUtil.isEmpty(paramList)){
            throw new MochaWSException("MochaServerParameter  is null");
        }


        server.addConnectListener(client -> {
            log.info("Connect client sessionId : {}; RemoteAddress {}", client.getSessionId(), client.getRemoteAddress().toString());
            Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
            MochaSocketConnectHandler handler = HandlerMapping.getSocketConnectHandler();
            handler.connect(params, client);
        });

        server.addDisconnectListener(client -> {
            log.info("Disconnect client sessionId : {}; RemoteAddress {}", client.getSessionId(), client.getRemoteAddress().toString());
            MochaSocketCloseHandler closeHandler = HandlerMapping.getSocketCloseHandler();
            closeHandler.close(client);
        });


        for (MochaServerParameter parameter : paramList){
            if (StrUtil.isNotBlank(parameter.getNameSpace())){
                String nameSpace = parameter.getNameSpace().startsWith("/") ? parameter.getNameSpace() : "/"+parameter.getNameSpace();
                final SocketIONamespace namespace = server.addNamespace(nameSpace);
                namespace.addEventListener(parameter.getEvent(),   String.class,  new MochaTextListener(parameter.getNameSpace(),  parameter.getEvent()));
            }else {
                server.addEventListener(parameter.getEvent(),   String.class,  new MochaTextListener(parameter.getNameSpace(),  parameter.getEvent()));
            }
        }

        log.info("------------start---------");
        server.start();

    }




    private Configuration buildConfiguration(MochaSocketConfigProperties properties) {
        Integer port = Optional.ofNullable(properties.getPort()).orElse(properties.getServerPort());
        if (null == port) {
            throw new MochaWSException("Server port is null");
        }
        Configuration config = new Configuration();
        config.setHostname(properties.getHost());
        config.setPort(port);
        config.setBossThreads(1);
        config.setMaxFramePayloadLength(256 * 1024);
        config.setMaxHttpContentLength(256 * 1024);
        return config;
    }


}
